#include <stdio.h>
#include <stdlib.h>
+typedef struct ICC {
+ char *data;
+ int length;
+
+ int tags;
+ int headpos;
+ int o, no;
+ int p;
+ int psize;
+} ICC;
+
+ICC *icc_state_new (char *data, int length, int tags);
+
+ICC *icc_state_new (char *data, int length, int tags)
+{
+ ICC *ret = babl_calloc (sizeof (ICC), 1);
+ ret->data = data;
+ ret->length = length;
+ ret->tags = tags;
+
+ return ret;
+}
+
+
+
#define ICC_HEADER_LEN 128
#define TAG_COUNT_OFF ICC_HEADER_LEN
char str[5];
} sign_t;
-#define icc_write(type, offset, value) write_##type(icc,length,offset,value)
-#define icc_read(type, offset) read_##type(icc,length,offset)
+#define icc_write(type, offset, value) write_##type(state,offset,value)
+#define icc_read(type, offset) read_##type(state,offset)
-static void write_u8 (char *icc, int length, int offset, uint8_t value)
+static void write_u8 (ICC *state, int offset, uint8_t value)
{
- if (offset < 0 || offset > length)
+ if (offset < 0 || offset >= state->length)
return;
- *(uint8_t*) (&icc[offset]) = value;
+ *(uint8_t*) (&state->data[offset]) = value;
}
-static void write_s8 (char *icc, int length, int offset, int8_t value)
+static void write_s8 (ICC *state, int offset, int8_t value)
{
- if (offset < 0 || offset > length)
+ if (offset < 0 || offset >= state->length)
return;
- *(int8_t*) (&icc[offset]) = value;
+ *(int8_t*) (&state->data[offset]) = value;
}
-static int read_u8 (const char *icc, int length, int offset)
+static int read_u8 (ICC *state, int offset)
{
/* all reading functions take both the char *pointer and the length of the
* buffer, and all reads thus gets protected by this condition.
*/
- if (offset < 0 || offset > length)
+ if (offset < 0 || offset > state->length)
return 0;
- return *(uint8_t*) (&icc[offset]);
+ return *(uint8_t*) (&state->data[offset]);
}
-static int read_s8 (const char *icc, int length, int offset)
+static int read_s8 (ICC *state, int offset)
{
- if (offset < 0 || offset > length)
+ if (offset < 0 || offset > state->length)
return 0;
- return *(int8_t*) (&icc[offset]);
+ return *(int8_t*) (&state->data[offset]);
}
-static void write_s16 (char *icc, int length, int offset, int16_t value)
+static void write_s16 (ICC *state, int offset, int16_t value)
{
- write_s8 (icc, length, offset + 0, value >> 8);
- write_u8 (icc, length, offset + 1, value & 0xff);
+ write_s8 (state, offset + 0, value >> 8);
+ write_u8 (state, offset + 1, value & 0xff);
}
-static int16_t read_s16 (const char *icc, int length, int offset)
+static int16_t read_s16 (ICC *state, int offset)
{
return icc_read (u8, offset + 1) +
- (read_s8 (icc, length, offset + 0) << 8);
+ (read_s8 (state, offset + 0) << 8); //XXX: transform to icc_read macro
}
-static uint16_t read_u16 (const char *icc, int length, int offset)
+static uint16_t read_u16 (ICC *state, int offset)
{
return icc_read (u8, offset + 1) +
(icc_read (u8, offset + 0) << 8);
}
-static void write_u16 (char *icc, int length, int offset, uint16_t value)
+static void write_u16 (ICC *state, int offset, uint16_t value)
{
- write_u8 (icc, length, offset + 0, value >> 8);
- write_u8 (icc, length, offset + 1, value & 0xff);
+ write_u8 (state, offset + 0, value >> 8);
+ write_u8 (state, offset + 1, value & 0xff);
}
-static u8f8_t read_u8f8_ (const char *icc, int length, int offset)
+static u8f8_t read_u8f8_ (ICC *state, int offset)
{
u8f8_t ret ={icc_read (u8, offset),
icc_read (u8, offset + 1)};
return ret;
}
-static s15f16_t read_s15f16_ (const char *icc, int length, int offset)
+static s15f16_t read_s15f16_ (ICC *state, int offset)
{
s15f16_t ret ={icc_read (s16, offset),
icc_read (u16, offset + 2)};
return ret;
}
-static void write_s15f16_ (char *icc, int length, int offset, s15f16_t val)
+static void write_s15f16_ (ICC *state, int offset, s15f16_t val)
{
icc_write (s16, offset, val.integer),
icc_write (u16, offset + 2, val.fraction);
return fix.integer + fix.fraction / 255.0;
}
-static void write_s15f16 (char *icc, int length, int offset, double value)
+static void write_s15f16 (ICC *state, int offset, double value)
{
- write_s15f16_ (icc, length, offset, d_to_s15f16 (value));
+ write_s15f16_ (state, offset, d_to_s15f16 (value));
}
-static double read_s15f16 (const char *icc, int length, int offset)
+static double read_s15f16 (ICC *state, int offset)
{
- return s15f16_to_d (read_s15f16_ (icc, length, offset));
+ return s15f16_to_d (read_s15f16_ (state, offset));
}
-static double read_u8f8 (const char *icc, int length, int offset)
+static double read_u8f8 (ICC *state, int offset)
{
- return u8f8_to_d (read_u8f8_ (icc, length, offset));
+ return u8f8_to_d (read_u8f8_ (state, offset));
}
static inline void print_u8f8 (u8f8_t fix)
}
}
-static void write_u32 (char *icc,
- int length,
- int offset,
- uint32_t value)
+static void write_u32 (ICC *state, int offset, uint32_t value)
{
int i;
for (i = 0; i < 4; i ++)
{
- write_u8 (icc, length, offset + i,
+ write_u8 (state, offset + i,
(value & 0xff000000) >> 24
);
value <<= 8;
}
}
-static uint32_t read_u32 (const char *icc, int length, int offset)
+static uint32_t read_u32 (ICC *state, int offset)
{
return icc_read (u8, offset + 3) +
(icc_read (u8, offset + 2) << 8) +
(icc_read (u8, offset + 0) << 24);
}
-static sign_t read_sign (const char *icc, int length,
- int offset)
+static sign_t read_sign (ICC *state, int offset)
{
sign_t ret;
ret.str[0]=icc_read (u8, offset);
return ret;
}
-static void write_sign (char *icc, int length,
- int offset, char *sign)
+static void write_sign (ICC *state, int offset, const char *sign)
{
int i;
for (i = 0; i < 4; i ++)
/* looks up offset and length for a specific icc tag
*/
-static int icc_tag (const char *icc, int length,
+static int icc_tag (ICC *state,
const char *tag, int *offset, int *el_length)
{
int tag_count = icc_read (u32, TAG_COUNT_OFF);
return 0;
}
-static const Babl *babl_trc_from_icc (const char *icc,
- int length,
- char **error)
+static const Babl *babl_trc_from_icc (ICC *state, int offset,
+ char **error)
{
- int offset = 0;
{
int count = icc_read (u32, offset + 8);
int i;
}
else
{
- return babl_trc_gamma (2.2);
-
+ return babl_trc_gamma (10.0);
// XXX: todo implement a curve trc babl type
// as well as detect sRGB curve from LUTs
return NULL;
}
+static void icc_allocate_tag (ICC *state, const char *tag, int size)
+{
+ state->no+=((4-state->o)%4);state->o = state->no;state->psize = size;
+ icc_write (sign, 128 + 4 + 4 * state->headpos++, tag);
+ icc_write (u32, 128 + 4 + 4 * state->headpos++, state->o);
+ icc_write (u32, 128 + 4 + 4 * state->headpos++, size);
+ state->p = state->no;\
+ state->no+=size;
+}
+
+static void icc_duplicate_tag(ICC *state, const char *tag)
+{
+ icc_write (sign, 128 + 4 + 4 * state->headpos++, tag);
+ icc_write (u32, 128 + 4 + 4 * state->headpos++, state->p);
+ icc_write (u32, 128 + 4 + 4 * state->headpos++, state->psize);
+}
const char *babl_space_rgb_to_icc (const Babl *babl, int *ret_length)
{
const BablSpace *space = &babl->space;
static char icc[8192];
int length=4095;
+ ICC *state = icc_state_new (icc, length, 10);
+
icc[length]=0;
-#if 1
+#if 0
icc_write (s8, 8,-2);
assert (icc_read (s8, 8) == -2);
icc_write (s8, 8, 3); // ICC verison
icc_write (sign, 36, "acsp"); // changes
-
{
- int headpos = 0;
- int tags;
- int o, no;
- int p = 0;
- int psize = 0;
-
- tags = 10;
- no = o = 128 + 4 + 12 * tags;
-
- icc_write (u32, 128, tags);
-#define icc_allocate_tag(tag, size) \
- no+=((4-o)%4);o = no;psize = size;\
- icc_write (sign, 128 + 4 + 4 * headpos++, tag);\
- icc_write (u32, 128 + 4 + 4 * headpos++, o);\
- icc_write (u32, 128 + 4 + 4 * headpos++, size);\
- p = no;\
- no+=size;
-#define icc_duplicate_tag(tag) \
- icc_write (sign, 128 + 4 + 4 * headpos++, tag);\
- icc_write (u32, 128 + 4 + 4 * headpos++, p); \
- icc_write (u32, 128 + 4 + 4 * headpos++, psize);
-
- icc_allocate_tag ("wtpt", 20);
- icc_write (sign,o, "XYZ ");
- icc_write (u32, o + 4, 0);
- icc_write (s15f16, o + 8, space->whitepoint[0]);
- icc_write (s15f16, o + 12, space->whitepoint[1]);
- icc_write (s15f16, o + 16, space->whitepoint[2]);
-
- icc_allocate_tag ("rXYZ", 20);
- icc_write (sign,o, "XYZ ");
- icc_write (u32, o + 4, 0);
- icc_write (s15f16, o + 8, space->RGBtoXYZ[0]);
- icc_write (s15f16, o + 12, space->RGBtoXYZ[3]);
- icc_write (s15f16, o + 16, space->RGBtoXYZ[6]);
-
- icc_allocate_tag ("gXYZ", 20);
- icc_write (sign,o, "XYZ ");
- icc_write (u32, o + 4, 0);
- icc_write (s15f16, o + 8, space->RGBtoXYZ[1]);
- icc_write (s15f16, o + 12, space->RGBtoXYZ[4]);
- icc_write (s15f16, o + 16, space->RGBtoXYZ[7]);
-
- icc_allocate_tag ("bXYZ", 20);
- icc_write (sign,o, "XYZ ");
- icc_write (u32, o + 4, 0);
- icc_write (s15f16, o + 8, space->RGBtoXYZ[2]);
- icc_write (s15f16, o + 12, space->RGBtoXYZ[5]);
- icc_write (s15f16, o + 16, space->RGBtoXYZ[8]);
-
- icc_allocate_tag ("rTRC", 14);
- icc_write (sign,o, "curv");
- icc_write (u32, o + 4, 0);
- icc_write (u32, o + 8, 1);
- icc_write (u16, o + 12, 334);
+ state->tags = 10; /* note: we could reserve a couple of spots and
+ still use a very simple allocator and
+ still be valid - albeit with tiny waste of
+ space.
+ */
+ state->no = state->o = 128 + 4 + 12 * state->tags;
+
+ icc_write (u32, 128, state->tags);
+
+ icc_allocate_tag (state, "wtpt", 20);
+ icc_write (sign, state->o, "XYZ ");
+ icc_write (u32, state->o + 4, 0);
+ icc_write (s15f16, state->o + 8, space->whitepoint[0]);
+ icc_write (s15f16, state->o + 12, space->whitepoint[1]);
+ icc_write (s15f16, state->o + 16, space->whitepoint[2]);
+
+ icc_allocate_tag (state, "rXYZ", 20);
+ icc_write (sign, state->o, "XYZ ");
+ icc_write (u32, state->o + 4, 0);
+ icc_write (s15f16, state->o + 8, space->RGBtoXYZ[0]);
+ icc_write (s15f16, state->o + 12, space->RGBtoXYZ[3]);
+ icc_write (s15f16, state->o + 16, space->RGBtoXYZ[6]);
+
+ icc_allocate_tag (state, "gXYZ", 20);
+ icc_write (sign, state->o, "XYZ ");
+ icc_write (u32, state->o + 4, 0);
+ icc_write (s15f16, state->o + 8, space->RGBtoXYZ[1]);
+ icc_write (s15f16, state->o + 12, space->RGBtoXYZ[4]);
+ icc_write (s15f16, state->o + 16, space->RGBtoXYZ[7]);
+
+ icc_allocate_tag (state, "bXYZ", 20);
+ icc_write (sign, state->o, "XYZ ");
+ icc_write (u32, state->o + 4, 0);
+ icc_write (s15f16, state->o + 8, space->RGBtoXYZ[2]);
+ icc_write (s15f16, state->o + 12, space->RGBtoXYZ[5]);
+ icc_write (s15f16, state->o + 16, space->RGBtoXYZ[8]);
+
+ icc_allocate_tag (state, "rTRC", 14);
+ icc_write (sign, state->o, "curv");
+ icc_write (u32, state->o + 4, 0);
+ icc_write (u32, state->o + 8, 1);
+ icc_write (u16, state->o + 12, 334);
if (space->trc[0] == space->trc[1] &&
space->trc[0] == space->trc[2])
{
- icc_duplicate_tag ("gTRC");
- icc_duplicate_tag ("bTRC");
+ icc_duplicate_tag (state, "gTRC");
+ icc_duplicate_tag (state, "bTRC");
}
else
{
- icc_allocate_tag ("gTRC", 14);
- icc_write (sign,o, "curv");
- icc_write (u32, o + 4, 0);
- icc_write (u32, o + 8, 1); /* forcing a linear curve */
- icc_allocate_tag ("bTRC", 14);
- icc_write (sign,o, "curv");
- icc_write (u32, o + 4, 0);
- icc_write (u32, o + 8, 1); /* forcing a linear curve */
+ icc_allocate_tag (state, "gTRC", 14);
+ icc_write (sign, state->o, "curv");
+ icc_write (u32, state->o + 4, 0);
+ icc_write (u32, state->o + 8, 1); /* forcing a linear curve */
+ icc_allocate_tag (state, "bTRC", 14);
+ icc_write (sign, state->o, "curv");
+ icc_write (u32, state->o + 4, 0);
+ icc_write (u32, state->o + 8, 1); /* forcing a linear curve */
}
{
char str[128];
int i;
sprintf (str, "babl");
- icc_allocate_tag("desc", 100 + strlen (str) + 1);
- icc_write (sign,o,"desc");
- icc_write (u32, o + 4, 0);
- icc_write (u32, o + 8, strlen(str));
+ icc_allocate_tag(state, "desc", 100 + strlen (str) + 1);
+ icc_write (sign, state->o,"desc");
+ icc_write (u32, state->o + 4, 0);
+ icc_write (u32, state->o + 8, strlen(str));
for (i = 0; str[i]; i++)
- icc_write (u8, o + 12 + i, str[i]);
+ icc_write (u8, state->o + 12 + i, str[i]);
- icc_duplicate_tag ("dmnd");
+ icc_duplicate_tag (state, "dmnd");
}
{
char str[128];
int i;
sprintf (str, "CC0/public domain");
- icc_allocate_tag("cprt", 8 + strlen (str) + 1);
- icc_write (sign,o, "text");
- icc_write (u32, o + 4, 0);
+ icc_allocate_tag(state, "cprt", 8 + strlen (str) + 1);
+ icc_write (sign, state->o, "text");
+ icc_write (u32, state->o + 4, 0);
for (i = 0; str[i]; i++)
- icc_write (u8, o + 8 + i, str[i]);
+ icc_write (u8, state->o + 8 + i, str[i]);
}
- icc_write (u32, 0, no + 3);
- length = no + 3;
+ icc_write (u32, 0, state->no + 3);
+ length = state->no + 3;
}
if (ret_length)
*ret_length = length;
+
+ babl_free (state);
return icc;
}
int length,
char **error)
{
+ ICC *state = icc_state_new ((char*)icc, length, 0);
+
int profile_size = icc_read (u32, 0);
int icc_ver_major = icc_read (u8, 8);
const Babl *trc_red = NULL;
if (profile_size != length)
{
*error = "icc profile length inconsistency";
- return NULL;
}
- if (icc_ver_major > 2)
+ else if (icc_ver_major > 2)
{
*error = "only ICC v2 profiles supported";
- return NULL;
}
+ else
+ {
profile_class = icc_read (sign, 12);
if (strcmp (profile_class.str, "mntr"))
- {
*error = "not a monitor-class profile";
- return NULL;
- }
+ else
+ {
color_space = icc_read (sign, 16);
if (strcmp (color_space.str, "RGB "))
- {
*error = "not defining an RGB space";
- return NULL;
}
+ }
+
{
int offset, element_size;
- if (icc_tag (icc, length, "rTRC", &offset, &element_size))
+ if (!*error && icc_tag (state, "rTRC", &offset, &element_size))
{
- trc_red = babl_trc_from_icc (icc + offset, element_size, error);
- if (*error) return NULL;
+ trc_red = babl_trc_from_icc (state, offset, error);
}
- if (icc_tag (icc, length, "gTRC", &offset, &element_size))
+ if (!*error && icc_tag (state, "gTRC", &offset, &element_size))
{
- trc_green = babl_trc_from_icc (icc + offset, element_size, error);
- if (*error) return NULL;
+ trc_green = babl_trc_from_icc (state, offset, error);
}
- if (icc_tag (icc, length, "bTRC", &offset, &element_size))
+ if (!*error && icc_tag (state, "bTRC", &offset, &element_size))
{
- trc_blue = babl_trc_from_icc (icc + offset, element_size, error);
- if (*error) return NULL;
+ trc_blue = babl_trc_from_icc (state, offset, error);
}
}
- if (!trc_red || !trc_green || !trc_blue)
+
+ if (!*error && (!trc_red || !trc_green || !trc_blue))
{
*error = "missing TRCs";
- return NULL;
}
- if (icc_tag (icc, length, "rXYZ", NULL, NULL) &&
- icc_tag (icc, length, "gXYZ", NULL, NULL) &&
- icc_tag (icc, length, "bXYZ", NULL, NULL) &&
- icc_tag (icc, length, "wtpt", NULL, NULL))
+ if (*error)
+ {
+ babl_free (state);
+ return NULL;
+ }
+
+ if (icc_tag (state, "rXYZ", NULL, NULL) &&
+ icc_tag (state, "gXYZ", NULL, NULL) &&
+ icc_tag (state, "bXYZ", NULL, NULL) &&
+ icc_tag (state, "wtpt", NULL, NULL))
{
int offset, element_size;
double rx, gx, bx;
double wX, wY, wZ;
- icc_tag (icc, length, "rXYZ", &offset, &element_size);
+ icc_tag (state, "rXYZ", &offset, &element_size);
rx = icc_read (s15f16, offset + 8 + 4 * 0);
ry = icc_read (s15f16, offset + 8 + 4 * 1);
rz = icc_read (s15f16, offset + 8 + 4 * 2);
- icc_tag (icc, length, "gXYZ", &offset, &element_size);
+ icc_tag (state, "gXYZ", &offset, &element_size);
gx = icc_read (s15f16, offset + 8 + 4 * 0);
gy = icc_read (s15f16, offset + 8 + 4 * 1);
gz = icc_read (s15f16, offset + 8 + 4 * 2);
- icc_tag (icc, length, "bXYZ", &offset, &element_size);
+ icc_tag (state, "bXYZ", &offset, &element_size);
bx = icc_read (s15f16, offset + 8 + 4 * 0);
by = icc_read (s15f16, offset + 8 + 4 * 1);
bz = icc_read (s15f16, offset + 8 + 4 * 2);
- icc_tag (icc, length, "wtpt", &offset, &element_size);
+ icc_tag (state, "wtpt", &offset, &element_size);
wX = icc_read (s15f16, offset + 8);
wY = icc_read (s15f16, offset + 8 + 4);
wZ = icc_read (s15f16, offset + 8 + 4 * 2);
+
+ babl_free (state);
return babl_space_rgb_matrix (NULL,
wX, wY, wZ,
rz, gz, bz,
trc_red, trc_green, trc_blue);
}
- else if (icc_tag (icc, length, "chrm", NULL, NULL) &&
- icc_tag (icc, length, "wtpt", NULL, NULL))
+ else if (icc_tag (state, "chrm", NULL, NULL) &&
+ icc_tag (state, "wtpt", NULL, NULL))
{
int offset, element_size;
double red_x, red_y, green_x, green_y, blue_x, blue_y;
int channels, phosporant;
- icc_tag (icc, length, "chrm", &offset, &element_size);
+ icc_tag (state, "chrm", &offset, &element_size);
channels = icc_read (u16, offset + 8);
phosporant = icc_read (u16, offset + 10);
blue_x = icc_read (s15f16, offset + 28);
blue_y = icc_read (s15f16, offset + 28 + 4);
- icc_tag (icc, length, "wtpt", &offset, &element_size);
+ icc_tag (state, "wtpt", &offset, &element_size);
{
double wX = icc_read (s15f16, offset + 8);
double wY = icc_read (s15f16, offset + 8 + 4);
double wZ = icc_read (s15f16, offset + 8 + 4 * 2);
+ babl_free (state);
return babl_space_rgb_chromaticities (NULL,
wX / (wX + wY + wZ),
}
*error = "didnt find RGB primaries";
+ babl_free (state);
return NULL;
}